home *** CD-ROM | disk | FTP | other *** search
- (* procedure to convert reals to strings by Doug Harrison *)
- {$M+}
- {$E+}
- PROGRAM mock;
-
- CONST
-
- {$I A:\GEMCONST.PAS}
-
- TYPE STR12 = STRING [ 12 ];
-
-
- {$I A:\GEMTYPE.PAS}
-
- {$I A:\GEMSUBS.PAS}
-
-
-
- PROCEDURE REAL_TO_STRING ( real_num : REAL;
- VAR string_real : STRING;
- digits : INTEGER;
- sci_not : BOOLEAN );
-
- (* real_num : real number to be converted into a string
- string_real : working variable that also passes string result to caller
- digits : specifies # of digits to be displayed right of decimal,
- valid values are 0-11
- sci_not : flag which determines whether to express in sci. not. or not
- *)
-
- (* FORMAT of string returned is:
- sci. not.:
- sign ( - or SPACE ), #.#####... , E, sign ( - or nothing ), ##.
- non-sci. not. :
- sign ( - or SPACE ), ####.####.
- *)
-
- (* Round-off errors of the nature x.xxxxxxx999 are corrected; consequently,
- any number with a sequence of 3 or more terminal 9's
- is affected, even if this is NOT an artifact. This should rarely be a
- problem. Also, if a number is to be expressed in expanded form, the
- magnitude of the exponent plus the # of digits to be displayed can not
- exceed 8, since LONG_ROUND generates long_ints- size < 2e9. This is not
- too severe a problem since only 11 digits of precision are supported
- anyway. That is, specifying 4 digits for the # 100,000,000.9012 is
- meaningless since the number is rounded to 100,000,000.9 as it becomes
- a REAL. The last digits are unavailable to real_to_string. In such
- cases, no action is performed on the number- it emerges untouched by
- the rounding function. Also, note that the detection of 999 occurs after
- conversion to 1 <= mag_num < 10. Thus, 99,999,999,999 becomes 9.9999999999
- which indicates a rounding error.
- *)
-
- LABEL 1;
- TYPE STR1 = STRING [ 1 ];
- VAR mag_num : REAL;
- c ,i , j, len,
- start_delete,
- end_delete : INTEGER;
- sign_exp : STR1;
- temp : STRING;
- found : BOOLEAN;
- last : ARRAY [ 1..11 ] OF STR1;
-
-
-
- PROCEDURE ADJUST_TO_SPECIFIED_LENGTH;
-
- (* adjusts appearance following rounding *)
-
- VAR dec_pos : INTEGER;
-
- BEGIN
-
- dec_pos := POS ( '.' , string_real );
- WHILE LENGTH ( string_real ) < dec_pos + digits DO
- string_real := CONCAT ( string_real,'0' );
- WHILE LENGTH ( string_real ) > dec_pos + digits DO
- DELETE ( string_real , LENGTH ( string_real ) , 1 );
- IF POS ( '.' , string_real ) = LENGTH ( string_real )
- THEN DELETE ( string_real , LENGTH ( string_real ) , 1 );
-
- END; (* adjust_to_specified_length *)
-
- PROCEDURE DO_EXPONENT;
-
- BEGIN
- temp := '';
- IF c >= 30 THEN BEGIN
- temp := '3';
- c := c - 30;
- END;
- IF c >= 20 THEN BEGIN
- temp := '2';
- c := c - 20;
- END;
- IF c >= 10 THEN BEGIN
- temp := '1';
- c := c - 10;
- END;
- temp := CONCAT ( temp , CHR ( c + 48 ) );
- adjust_to_specified_length;
- string_real := CONCAT ( string_real,'E' ,sign_exp,temp );
- END;
-
- PROCEDURE SUCCESSOR ( VAR num : STR1 );
-
- (* used to "increment" a string digit *)
-
- BEGIN
- IF num = '8'
- THEN num := '9';
- IF num = '7'
- THEN num := '8';
- IF num = '6'
- THEN num := '7';
- IF num = '5'
- THEN num := '6';
- IF num = '4'
- THEN num := '5';
- IF num = '3'
- THEN num := '4';
- IF num = '2'
- THEN num := '3';
- IF num = '1'
- THEN num := '2';
- IF num = '0'
- THEN num := '1';
- END; (* SUCCESSOR *)
-
- PROCEDURE REMOVE_9s;
-
- VAR i , j : INTEGER;
- BEGIN
-
- (* Get rid of artifactual "999" generated, if any *)
-
- temp := COPY ( string_real , 4 , 10 );
-
- i := 10;
- found := FALSE;
-
- WHILE ( NOT found ) AND ( i >= 1 ) DO
- IF temp [ i ] <> '9'
- THEN found := TRUE
- ELSE i := i - 1;
- i := i + 1;
-
- IF i <= 8
- THEN BEGIN
-
- FOR j := 1 TO 10 DO
- last [ j ] := 'f';
-
- DELETE ( string_real ,i + 3, LENGTH(string_real)-(i+2) );
- len := LENGTH ( string_real );
- FOR i := 1 TO len DO
- last [ i ] := COPY ( string_real , i , 1 );
- IF len = 3 (* x.9999999999 *)
- THEN BEGIN
- IF last [ 2 ] = '9'
- THEN BEGIN
- last [ 2 ] := '1';
- last [ 4 ] := '0';
- IF sign_exp = ''
- THEN c := c + 1
- ELSE c := c - 1;
- END
- ELSE BEGIN
- successor ( last [ 2 ] );
- last [ 4 ] := '0';
- END;
- END
- ELSE successor ( last [ len ] ); (* x.xxxx999999 *)
- (* needn't check here if last[len]=9; it CAN'T be,
- as it would have been a part of the string of 9's
- *)
-
- string_real := '';
- i := 1;
-
- WHILE ( last [ i ] <> 'f' ) AND ( i < 11 ) DO
- (* recreate string_real *)
- BEGIN
- string_real := CONCAT ( string_real , last [ i ] );
- i := i + 1;
- END;
-
- END;
-
- END; (* REMOVE_9s *)
-
- BEGIN (* REAL_TO_STRING *)
-
- IF real_num <> 0.0
- THEN BEGIN
- IF real_num < 0.0 (* sign of number *)
- THEN string_real := '-'
- ELSE string_real := ' ';
-
- IF (( real_num < 1.0 ) AND ( real_num > 0.0 )) OR
- (( real_num < 0.0 ) AND ( real_num > -1.0 ))
- THEN sign_exp := '-'
- ELSE sign_exp := '';
-
- mag_num := ABS (real_num); (* got sign, so work with number
- magnitude ! *)
- c := 0; (* c counts the number of times the
- number can be multiplied or div-
- ided by 10 so that finally
- 1 <= number < 10 *)
- IF mag_num >= 10.0 (* make 1 <= number < 10 *)
- THEN REPEAT
- mag_num := mag_num / 10.0;
- c := c+1;
- UNTIL mag_num < 10.0
- ELSE IF mag_num < 1.0
- THEN REPEAT
- mag_num := mag_num * 10.0;
- c := c+1;
- UNTIL mag_num >= 1.0;
-
- (* Round mag_num to specified # of digits *)
-
- IF ( sci_not ) AND ( digits <= 8 )
- THEN mag_num := LONG_ROUND ( mag_num * PwrOfTen ( digits ) ) /
- PwrOfTen ( digits );
-
- IF NOT sci_not THEN BEGIN (* Round to spec # digit if possible *)
- IF (c+digits <= 8) AND
- ((real_num > 1 ) OR ( real_num < -1)) THEN
- mag_num := LONG_ROUND (mag_num*PwrOfTen(c+digits)) /
- PwrOfTen ( c + digits );
- (* bug fix *) IF ( real_num < 1 ) AND ( real_num > -1 ) THEN BEGIN
- IF ( digits-c <= 8 ) AND ( digits-c >= -8 ) THEN BEGIN
- IF digits-c >= 0 THEN
- mag_num:= LONG_ROUND (mag_num*PwrOfTen(digits-c)) /
- PwrOfTen ( digits-c )
- ELSE mag_num := LONG_ROUND (mag_num/
- PwrOfTen(ABS(digits-c)))*
- PwrOfTen ( ABS(digits-c) );
- END;
- IF mag_num = 0 THEN GOTO 1;
- END;
- END;
-
- (* reals have 11 digits of precision *)
- (* convert REAL to a string equivalent *)
-
- FOR i := 1 TO 11 DO
- BEGIN
- j := TRUNC (mag_num); (* apparently if mag_num =
- 9.999999 then TRUNC
- returns a value of 10
- but if mag_num=9.9999999999
- it returns 9- strange!
- So adjust c for this *)
- (* bug fix *) IF ( j = 10 ) AND ( i = 1 ) THEN BEGIN
- IF sign_exp = '' THEN BEGIN
- string_real := CONCAT (string_real,CHR (1+48));
- c := c+1;
- END
- ELSE BEGIN
- IF sign_exp = '-' THEN BEGIN
- string_real:=CONCAT (string_real,CHR(1+48));
- c := c-1;
- END;
- END;
- END
- ELSE string_real := CONCAT (string_real,CHR (j+48));
- mag_num := ( mag_num - j ) * 10.0;
- IF i = 1
- THEN string_real := CONCAT ( string_real , '.' );
- END; (* FOR i *)
-
- remove_9s;
-
- IF NOT sci_not (* express in expanded form *)
- THEN BEGIN
- IF sign_exp = '-' THEN BEGIN (* mag_num < 1, mag_num <> 0 *)
- temp := COPY ( string_real , 1 , 1 );
- temp := CONCAT ( temp,'0.' );
- FOR i := 1 TO c - 1 DO
- temp := CONCAT ( temp , '0' );
- DELETE ( string_real , 1 , 1 );
- DELETE ( string_real , 2 , 1 );
- string_real := CONCAT ( temp , string_real );
- adjust_to_specified_length;
- END
- ELSE BEGIN
- DELETE ( string_real , 3 , 1 );
- IF ( 3 + c ) > LENGTH ( string_real )
- THEN FOR i := LENGTH( string_real ) TO ( 2 + c ) DO
- string_real := CONCAT ( string_real ,
- '0' );
- INSERT ( '.' , string_real , 3 + c );
- adjust_to_specified_length;
- END;
- END
- ELSE do_exponent; (* express in scientific notation *)
- END (* begin of first then clause *)
-
- ELSE BEGIN (* real_num = 0 *)
-
- 1: string_real := ' 0';
- FOR i := 1 to digits DO
- BEGIN
-
- IF i = 1
- THEN string_real := CONCAT ( string_real , '.' );
- string_real := CONCAT ( string_real , '0' );
-
- END;
- END;
-
- END; (* REAL_TO_STRING *)
-
- BEGIN (* dummy program for modular compilation *)
- END.
-